
/** 
 * content script 中无法使用Element Plus；封装纯js实现的弹窗提示的类 
 * 弹窗内容可以是可以是HTML的tag, 如 <span> xxxx <br> yyyyy </span>
 * 可同时弹出多个弹窗
 * */
export interface DomMessageParams {
  content: string, // 弹窗提示的内容，可以是HTML的tag, 如 <span> xxxx <br> yyyyy </span>
  duration?: number
}

const colors:Record< 'error' | 'success', '#f56c6c' | '#67c23a' > = {
  error: '#f56c6c',
  success: '#67c23a'
}

export interface DomMessageInstanceType {
  error(params:DomMessageParams):void,
  success(params:DomMessageParams):void
}

const defaultConfig = {
  duration: 5500
}

class DomMessage implements DomMessageInstanceType {
  content: string = ''
  duration: number = defaultConfig.duration
  type: 'error' | 'success' = 'error'
  color: '#67c23a' | '#f56c6c' = colors.error

  className:string = 'dom__message__3469'
  classIndex: number = 0
  firstTop:number = 80
  distanceH:number = 20
  opacityTime:number = 800

  constructor(){}

  generateParams(this:DomMessage, params:DomMessageParams) {
    const {content, duration} = params

    this.content = `<span>${content}</span>`
    this.color = colors[this.type]
    this.duration = duration || this.duration
    this.duration = this.duration >= defaultConfig.duration ? this.duration : defaultConfig.duration
  }

  getTop(this:DomMessage) {
    const existDoms = document.querySelectorAll(`.${this.className}`)
    if(!existDoms.length) return this.firstTop
    const lastDom = existDoms[existDoms.length - 1]
    const {bottom} = lastDom.getBoundingClientRect()
    return bottom + this.distanceH
  }

  getStyle(this:DomMessage) {
    const {color} = this


    const style = `
      position: fixed;
      z-index: 9999;
      left: 50%;
      transform: translateX(-50%);
      top: ${this.getTop()}px;
      font-size: 16px;
      padding: 12px;
      max-width: calc(100% - 32px);
      border-radius: 8px;
      border: 1px solid skyblue;
      text-align: left;
      background: #f0f9eb;
      font-weight: bolder;
      color: ${color};
      opacity: 0;
      transition-property: top, opacity;
      transition-duration: 0.3s, 0.8s;
    `
    return style.trim()
  }

  createDom(this:DomMessage, classIndex:number) {
    const boxDom = document.createElement("div")
    boxDom.className = `${this.className}_${classIndex}`
    boxDom.classList.add(this.className)
    boxDom.style.cssText = this.getStyle()
    boxDom.insertAdjacentHTML('afterbegin',this.content)
    return boxDom
  }

  insertDom(this:DomMessage, dom:Element) {
    document.body.appendChild(dom)
  }

  delAllDom(this:DomMessage, classIndex:number){
    const dom = document.querySelector(`.${this.className}_${classIndex}`)
    dom && this.delSelfDom(dom)

    this.resetData()
    this.retsetDomPos()
  }

  resetData(this:DomMessage) {
    this.content = ''
    this.duration = defaultConfig.duration
    this.type = 'error'
    this.color = colors.error
  }

  retsetDomPos(this:DomMessage) {
    const existDoms = Array.from(document.querySelectorAll(`.${this.className}`) || {length:0})
    if(!existDoms.length) return
    let sumHeight = this.firstTop

    existDoms.forEach((el:any) => {
      el.style.top = `${sumHeight}px`
      sumHeight += el.offsetHeight + this.distanceH
    })
  }

  setOpacity(this:DomMessage, classIndex:number, opacity = 0) {
    const el = document.querySelector(`.${this.className}_${classIndex}`) as HTMLElement
    if(!el) return
    el.style.opacity = String(opacity)
  }

  delSelfDom(this:DomMessage, dom:Element) {
    dom.parentElement?.removeChild(dom)
  }

  openMessage(this:DomMessage, classIndex:number) {
    this.insertDom(this.createDom(classIndex))

    setTimeout(() => this.setOpacity(classIndex, 1), 80)
  }

  closeMessage(this:DomMessage, classIndex:number) {
    const delAllDom = this.delAllDom.bind(this)

    setTimeout(() => this.setOpacity(classIndex, 0), this.duration - this.opacityTime)

    setTimeout(() => {
      delAllDom(classIndex)
    }, this.duration)
  }


  error(this:DomMessage, params:DomMessageParams) {
    ++this.classIndex
    this.type = 'error'
    this.generateParams(params)

    this.openMessage(this.classIndex)
    this.closeMessage(this.classIndex)
  }

  success(this:DomMessage, params:DomMessageParams) {
    ++this.classIndex
    this.type = 'success'
    this.generateParams(params)

    this.openMessage(this.classIndex)
    this.closeMessage(this.classIndex)
  }
}

/** message 弹窗 */
export const DomMessageInstance = new DomMessage()
